package com.abe.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

import com.abe.strengthtrainer.R;

/**
 * @see 
 *      可以说重载onMeasure()，onLayout()，onDraw()三个函数构建了自定义View的外观形象（绘制流程：measure->layout
 *      ->draw）。
 * @see 再加上onTouchEvent()等重载视图的行为，可以构建任何我们需要的可感知到的自定义View。
 */
@SuppressLint("DrawAllocation")
public class PlaygroundView extends View implements Runnable {

	private Paint mPaint;
	@SuppressWarnings("unused")
	private Context mContext;
	private float mHeight;
	private float mWitdh;
	private int paintWidth;
	private int paintColor;
	private boolean fill;
	private int runwayNumber;
	private int runwayDivierColor;
	private int positionBallColor;
	/** 小球直径 */
	private float ballWidth;
	/** 小球轨道长度 */
	private float ballRunWayLength;
	/** 小球轨道圆半径 */
	private float ballRunWayRadius;
	/** 小球速度（px/100ms） */
	private float speed = 0;
	/** 小球圆心xy值 */
	float ballCenterX;
	float ballCenterY;

	private boolean isFrist = true;
	private boolean isRun = false;

	private float allDis;

	public float getAllDis() {
		return allDis;
	}

	public void setAllDis(float allDis) {
		this.allDis = allDis;
	}

	public PlaygroundView(Context context) {
		this(context, null);
	}

	public PlaygroundView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	/**
	 * 获得我自定义的样式属性
	 * 
	 * @param context
	 * @param attrs
	 * @param defStyle
	 */
	public PlaygroundView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		/**
		 * 获得我们所定义的自定义样式属性
		 */
		TypedArray typedArray = context.getTheme().obtainStyledAttributes(
				attrs, R.styleable.PlaygroundView, defStyle, 0);
		int n = typedArray.getIndexCount();
		for (int i = 0; i < n; i++) {
			int attr = typedArray.getIndex(i);
			switch (attr) {
			case R.styleable.PlaygroundView_paintColor:
				/** 操场主色 */
				paintColor = typedArray.getColor(attr,
						getResources().getColor(R.color.app_theme_color));
				break;
			case R.styleable.PlaygroundView_fill:
				/** 是否填充 */
				fill = typedArray.getBoolean(attr, false);
				break;
			case R.styleable.PlaygroundView_paintWidth:
				/** 画笔宽度 */
				paintWidth = typedArray.getDimensionPixelSize(attr, 2);
				break;
			case R.styleable.PlaygroundView_runwayNumber:
				/** 跑道数量 */
				runwayNumber = typedArray.getInteger(attr, 1);
				break;
			case R.styleable.PlaygroundView_runwayDivierColor:
				/** 跑道间隔线颜色 */
				runwayDivierColor = typedArray.getColor(attr, getResources()
						.getColor(R.color.app_theme_word_color));
				break;
			case R.styleable.PlaygroundView_positionBallColor:
				/** 位置小球颜色 */
				positionBallColor = typedArray.getColor(attr, getResources()
						.getColor(R.color.white));
				break;
			}
		}
		typedArray.recycle();
		mContext = context;
		init();
	}

	/**
	 * 由于onDraw()方法会不停的绘制 所以需要定义一个初始化画笔方法 避免导致不停创建造成内存消耗过大
	 */
	private void init() {
		mPaint = new Paint();
		isFrist = true;
		isRun = false;
	}

	private void setPaint(int color, boolean isFill) {
		/** 设置画笔为抗锯齿 */
		mPaint.setAntiAlias(true);
		/** 设置颜色 */
		mPaint.setColor(color);
		/**
		 * 画笔样式分三种： 1.Paint.Style.STROKE：描边 2.Paint.Style.FILL_AND_STROKE：描边并填充
		 * 3.Paint.Style.FILL：填充
		 */
		if (isFill) {
			mPaint.setStyle(Paint.Style.FILL);
		} else {
			mPaint.setStyle(Paint.Style.STROKE);
		}
		/**
		 * 设置描边的粗细，单位：像素px 注意：当setStrokeWidth(0)的时候描边宽度并不为0而是只占一个像素
		 */
		mPaint.setStrokeWidth(paintWidth);
	}

	@Override
	public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		/**
		 * 为整个View树计算实际的大小，即设置实际的高(对应属性:mMeasuredHeight)和宽(对应属性:
		 * mMeasureWidth)，每个View的控件的实际宽高都是由父视图和本身视图决定的
		 */

		/**
		 * 具体的调用链如下：
		 * ViewRoot根对象地属性mView(其类型一般为ViewGroup类型)调用measure()方法去计算View树的大小，回调
		 * View/ViewGroup对象的onMeasure()方法，该方法实现的功能如下：
		 * 
		 * @see 1、设置本View视图的最终大小，该功能的实现通过调用setMeasuredDimension()方法去设置实际的高(对应属性：
		 *      mMeasuredHeight)和宽(对应属性：mMeasureWidth) ；
		 * @see 
		 *      2、如果该View对象是个ViewGroup类型，需要重写该onMeasure()方法，对其子视图进行遍历的measure()过程
		 *      。
		 * 
		 * @see 2.1
		 *      对每个子视图的measure()过程，是通过调用父类ViewGroup.java类里的measureChildWithMargins
		 *      ()方法去
		 *      实现，该方法内部只是简单地调用了View对象的measure()方法。(由于measureChildWithMargins()
		 *      方法只是一个过渡 层更简单的做法是直接调用View对象的measure()方法)。
		 * 
		 *      整个measure调用流程就是个树形的递归过程
		 */
		mHeight = this.getMeasuredHeight();
		mWitdh = this.getMeasuredWidth();
	}

	@Override
	public void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		/** 主要作用 ：为将整个根据子视图的大小以及布局参数将View树放到合适的位置上 */
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		/**
		 * drawArc（画弧）
		 * 
		 * @param oval
		 *            :指定圆弧的外轮廓矩形区域。
		 * @param startAngle
		 *            : 圆弧起始角度，单位为度。
		 * @param sweepAngle
		 *            : 圆弧扫过的角度，顺时针方向，单位为度,从右中间开始为零度。
		 * @param useCenter
		 *            : 如果为True时，在绘制圆弧时将圆心包括在内，通常用来绘制扇形。关键是这个变量，下
		 */
		if (mHeight < mWitdh) {
			/** 两边半圆，中间矩形 **/
			setPaint(paintColor, fill);
			RectF oval_left = new RectF(0, 0, mHeight, mHeight);
			canvas.drawArc(oval_left, 90, 180, true, mPaint);
			RectF oval_center = new RectF(mHeight / 2, 0, mWitdh - mHeight / 2,
					mHeight);
			canvas.drawRect(oval_center, mPaint);
			RectF oval_right = new RectF(mWitdh - mHeight, 0, mWitdh, mHeight);
			canvas.drawArc(oval_right, -90, 180, true, mPaint);
			/** 绿色中心，两边半圆，中间矩形 */
			int playground_center_green = getResources().getColor(
					R.color.playground_center_green);
			setPaint(playground_center_green, fill);
			RectF green_center_left = new RectF(mHeight / 4, mHeight / 4,
					mHeight - mHeight / 4, mHeight * 2 / 4 + mHeight / 4);
			canvas.drawArc(green_center_left, 90, 180, true, mPaint);
			RectF green_center_center = new RectF(mHeight / 2, mHeight / 4,
					mWitdh - mHeight / 2, mHeight*3 / 4);
			canvas.drawRect(green_center_center, mPaint);
			RectF green_center_right = new RectF(
					mWitdh - mHeight + mHeight / 4, mHeight / 4, mWitdh
							- mHeight / 4, mHeight * 2 / 4 + mHeight / 4);
			canvas.drawArc(green_center_right, -90, 180, true, mPaint);
			/** 绘制跑道间隔线 **/
			setPaint(runwayDivierColor, false);
			int runwayDivierNumber = runwayNumber + 1;
			float runWayWidth = mHeight / 4 / runwayNumber;
			for (int i = 0; i < runwayDivierNumber; i++) {
				float margin = (i * runWayWidth);
				float radius = mHeight / 2 - margin;
				float diameter = 2 * radius;
				/** 两边半圆 **/
				RectF runway_oval_left = new RectF(margin, margin, mHeight
						- margin, diameter + margin);
				canvas.drawArc(runway_oval_left, 90, 180, false, mPaint);
				/** 跑道间隔线 **/
				canvas.drawLine(mHeight / 2, margin, mWitdh - mHeight / 2,
						margin, mPaint);
				canvas.drawLine(mHeight / 2, diameter + margin, mWitdh
						- mHeight / 2, diameter + margin, mPaint);
				RectF runway_oval_right = new RectF(mWitdh - mHeight + margin,
						margin, mWitdh - margin, diameter + margin);
				canvas.drawArc(runway_oval_right, -90, 180, false, mPaint);
			}
			/** 绘制小球 **/
			setPaint(positionBallColor, true);
			if (isFrist) {
				/** 小球直径 */
				ballWidth = runWayWidth * 3 / 4;
				/** 获取小球所在跑道 */
				int ballRunWay = runwayNumber % 2 == 0 ? runwayNumber / 2
						: runwayNumber / 2 + 1;
				/** 小球跑道边界 */
				float margin_top = (ballRunWay * runWayWidth);
				float margin_bottom = margin_top - runWayWidth;
				/** 小球初始位置（右下角） */
				ballCenterX = mWitdh - mHeight / 2;
				ballCenterY = (margin_top - margin_bottom) / 2 + mHeight
						- margin_top;
				/** 小球轨道圆半径 */
				ballRunWayRadius = (mHeight - (margin_top + margin_bottom)) / 2;
				/** 小球轨道长度 */
				ballRunWayLength = (float) (2 * ballRunWayRadius * Math.PI)
						+ (mWitdh - mHeight) * 2;
				isFrist = !isFrist;
			}
			canvas.drawCircle(ballCenterX, ballCenterY, ballWidth / 2, mPaint);
		}
	}

	@Override
	public void run() {
		isRun = true;
		while (isFrist) {
			/** 等待初始化完成 */
		}
		/**
		 * 使用while循环不断的刷新view的半径 当半径小于100每次增加10 invalidate()重绘view会报错
		 * android.view.ViewRootImpl$CalledFromWrongThreadException 是非主线程更新UI
		 * Android给提供postInvalidate();快捷方法来重绘view
		 * 现在明白了invalidate和postInvalidate的小区别了吧
		 */
		/** 周长一半 */
		float perimeter_half = ballRunWayLength / 2 - (mWitdh - mHeight);
		float line = mWitdh - mHeight;
		float dis_1 = perimeter_half;
		float dis_2 = perimeter_half + line;
		float dis_3 = perimeter_half * 2 + line;
		allDis = 0;
		while (true && isRun) {
			try {
				Thread.sleep(100);
				allDis = allDis + speed;
				float dis = allDis % ballRunWayLength;
				float temx;
				float temy;
				if (dis <= dis_1) {
					/** 求角度 */
					float degree = dis * 180 / perimeter_half;
					temx = (mWitdh - mHeight / 2)
							+ (ballRunWayRadius * (float) (Math.sin(degree
									* Math.PI / 180)));
					temy = mHeight
							/ 2
							+ (ballRunWayRadius * (float) (Math.cos(degree
									* Math.PI / 180)));
				} else if (dis > dis_1 && dis < dis_2) {
					/** 第二段 */
					dis = dis - dis_1;
					temx = mWitdh - mHeight / 2 - dis;
					temy = mHeight / 2 - ballRunWayRadius;
				} else if (dis >= dis_2 && dis <= dis_3) {
					/** 第三段 */
					dis = dis - dis_2;
					/** 求角度 */
					float degree = dis * 180 / perimeter_half;
					temx = mHeight
							/ 2
							- (ballRunWayRadius * (float) (Math.sin(degree
									* Math.PI / 180)));
					temy = mHeight
							/ 2
							- (ballRunWayRadius * (float) (Math.cos(degree
									* Math.PI / 180)));
				} else {
					/** 第四段 */
					dis = dis - dis_3;
					temx = mHeight / 2 + dis;
					temy = mHeight / 2 + ballRunWayRadius;
				}
				ballCenterX = temx;
				ballCenterY = temy;
				postInvalidate();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		/** 恢复原状 */
		isFrist = true;
		postInvalidate();
	}

	public boolean isRun() {
		return isRun;
	}

	public void setRun(boolean isRun) {
		this.isRun = isRun;
	}

	public float getSpeed() {
		return speed;
	}

	public void setSpeed(float speed) {
		this.speed = speed;
	}

	public int getPaintWidth() {
		return paintWidth;
	}

	public void setPaintWidth(int paintWidth) {
		this.paintWidth = paintWidth;
	}

	public int getPaintColor() {
		return paintColor;
	}

	public void setPaintColor(int paintColor) {
		this.paintColor = paintColor;
	}

	public int getRunwayNumber() {
		return runwayNumber;
	}

	public void setRunwayNumber(int runwayNumber) {
		this.runwayNumber = runwayNumber;
	}

	public int getRunwayDivierColor() {
		return runwayDivierColor;
	}

	public void setRunwayDivierColor(int runwayDivierColor) {
		this.runwayDivierColor = runwayDivierColor;
	}

	public int getPositionBallColor() {
		return positionBallColor;
	}

	public void setPositionBallColor(int positionBallColor) {
		this.positionBallColor = positionBallColor;
	}

	public float getBallRunWayLength() {
		return ballRunWayLength;
	}

	public void setBallRunWayLength(float ballRunWayLength) {
		this.ballRunWayLength = ballRunWayLength;
	}

	public float getBallRunWayRadius() {
		return ballRunWayRadius;
	}

	public void setBallRunWayRadius(float ballRunWayRadius) {
		this.ballRunWayRadius = ballRunWayRadius;
	}

}
